#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cstdlib>
#include <assert.h>
#include <unordered_map>
#include "../comm/logger.hpp"
#include "../comm/util.hpp"
namespace ns_model
{
    using namespace ns_util;
    class Question
    {
    public:
        int _id;                 // 题目编号(唯一)
        std::string _title;      // 题目标题
        std::string _difficulty; // 题目难度
        int _cpu_limit;          // 时间限制(s)
        int _mem_limit;          // 空间限制(KB)
        // 这三个内容是封装在文件里的
        std::string _desc;   // 题目描述
        std::string _header; // 题目预设代码
        std::string _tail;   // 题目测试用例(需要和预设代码拼成完整代码)
    };
    std::string questions_path = "./questions/";
    std::string questions_list = "./questions/questions_list";
    class Model
    {
    private:
        std::unordered_map<int, Question> _questions; // 题号和题目具体细节
    public:
        bool LoadQuestionList(const std::string &questions_list)
        // 将题目列表加载到内存中,如果加载失败说明无法获取题目,这个在线OJ系统就没有意义了
        {
            std::ifstream in(questions_list);
            if (in.is_open() == false)
            {
                FLOG("打开题目列表失败,请检查文件是否存在");
                return false;
            }
            std::string line;
            while (getline(in, line))
            {
                std::vector<std::string> tokens;
                String_Util::SplitString(line, &tokens, " ");
                if (tokens.size() != 5)
                {
                    WLOG("部分题目加载错误,请检查文件格式");
                    continue;
                }
                Question q;
                q._id = std::stoi(tokens[0]);
                q._title = tokens[1];
                q._difficulty = tokens[2];
                q._cpu_limit = std::stoi(tokens[3]);
                q._mem_limit = std::stoi(tokens[4]);
                std::string path = questions_path;
                // 拼接出保存desc,header和tail的文件路径
                path += std::to_string(q._id);
                path += "/";
                File_Util::Read_File(path + "desc.txt", q._desc, true);
                File_Util::Read_File(path + "header.cpp", q._header, true);
                File_Util::Read_File(path + "tail.cpp", q._tail, true);
                _questions.insert({q._id, q});
            }
            ILOG("题目列表加载完成");
            in.close();
            return true;
        }
        bool  GetAllQuestions(std::vector<Question>& out)
        {
            if(_questions.size()==0)
            {
                ELOG("题目列表加载失败");
                return false;
            }
            for(const auto& q:_questions)
            {
                out.push_back(q.second);
            }
            return true;
        }
        bool GetOneQuestion(int id,Question& out)
        {
            if(_questions.size()==0)
            {
                ELOG("题目列表加载失败");
                return false;
            }
            const auto& pos=_questions.find(id);
            if(pos==_questions.end())
            {
                ELOG("获取题目失败, 题目编号:%d",id);
                return false;
            }
            out=pos->second;
            return true;
        }
        Model()
        {
            assert(LoadQuestionList(questions_list));
            // 这里题目列表加载失败就直接终止程序,没有题目列表没有意义
        }
        ~Model()
        {
        }
    };
}